library MarineJump initializer init requires LegacySystem


	private function JumpDamage takes nothing returns nothing
		local unit u = getUnit(null,"jumpunit")
		call putInteger(null,"jumpunit",0)
		call SetUnitAnimation(u,"death")
		call UnitDamageTargetBJ(u,u,120.0,ATTACK_TYPE_MELEE,DAMAGE_TYPE_NORMAL)
		call UnitAddAbility(u,'A05S')
		call ShiftMoveSpeed(u,-80.0)
		call TriggerSleepAction(0)
		call ResetUnitAnimation(u)
		call PolledWait(2.5)
		call ShiftMoveSpeed(u,30.0)
		call PolledWait(2.5)
		call UnitRemoveAbility(u,'A05S')
		call ShiftMoveSpeed(u,50.0)
		set u = null
	endfunction

	private  function InsideTower takes real x, real y returns boolean
		return RectContainsCoords(gg_rct_Tower1,x,y) or RectContainsCoords(gg_rct_Tower2,x,y) or RectContainsCoords(gg_rct_Tower3,x,y) or RectContainsCoords(gg_rct_Tower4,x,y) or RectContainsCoords(gg_rct_Tower5,x,y) or RectContainsCoords(gg_rct_Tower6,x,y)
	endfunction

	private function hiphop_callback_inner takes timer t returns nothing
		local integer i = getInteger(t,"i")
		local integer momentum = getInteger(t,"momentum")
		local real x0 = getReal(t,"x0")
		local real y0 = getReal(t,"y0")
		local real x1 = getReal(t,"x1")
		local real y1 = getReal(t,"y1")
		local integer maxiter = R2I(SquareRoot((x1-x0)*(x1-x0)+(y1-y0)*(y1-y0))/20)
		local real s = i/(maxiter + 0.001)
		local unit u = getUnit(t,"u")
		if t==null then
		   call BJDebugMsg("Jump Failure. Contact System Administrator.")
		elseif u==null then
		   call FlushHandleLocals(t)
		   call DestroyTimer(t)
		elseif i>maxiter then
		   call putBoolean(u,"jumping",false)
		   call FlushHandleLocals(t)
		   call DestroyTimer(t)
		   call SetUnitFlyHeight(u,0.0,1000.0)
		   call SetUnitPathing(u,true)
		   if momentum==1 then
			   call UnitRemoveAbility(u,'A07O') //Footsteps animation
			   call UnitRemoveAbility(u,'A05O') //Jump failsafe
		   endif
		   if GetTerrainCliffLevel(x0,y0)-GetTerrainCliffLevel(x1,y1)>1 or GetUnitAbilityLevel(u,'Bslo')>0 or InsideTower(x0,y0) then
			   call putUnit(null,"jumpunit",u)
			   call JumpDamage.execute()
		   endif
		else
		   call PauseUnit(u,true)
		   call SetUnitX(u,(1.0-s)*x0 + s*x1)
		   call SetUnitY(u,(1.0-s)*y0 + s*y1)
		   call PauseUnit(u,false)
		   call putInteger(t,"i",i+1)
		endif
		set u = null
	endfunction

	private function hiphop_callback takes nothing returns nothing
		call hiphop_callback_inner(GetExpiredTimer())
	endfunction

	private function hippityhoppity takes unit u, real x0, real y0, real x1, real y1, integer momentum returns nothing
		local timer t = CreateTimer()
		local integer current = udg_Second
		if current-udg_JumpLimit!=0 then
			call AttachSoundToUnit(gg_snd_Jump,u)
			call SetSoundVolume(gg_snd_Jump,127)
			call StartSound(gg_snd_Jump)
		else
			set udg_JumpLimit=current
		endif
		call UnitAddAbility(u,'A05O')
		call UnitRemoveAbility(u,'A05O')
		call SetUnitPathing(u,false)
		call SetUnitFlyHeight(u,45.0,500.0)
		call putUnit(t,"u",u)
		call putReal(t,"x0",x0)
		call putReal(t,"y0",y0)
		call putReal(t,"x1",x1)
		call putReal(t,"y1",y1)
		call putInteger(t,"momentum",momentum)
		call putInteger(t,"i",1)
		call putBoolean(u,"jumping",true)
		call TimerStart(t,0.03,true,function hiphop_callback)
		set t = null
	endfunction

	private function JumpConditions takes nothing returns boolean
		local integer i = GetSpellAbilityId()
		return (i=='A05P' or i=='A05N' or i=='A05X' or i=='A07X') and GetUnitAbilityLevel(GetTriggerUnit(),'B001')<1 and GetUnitAbilityLevel(GetTriggerUnit(),'Beng')<1 //no suppressive fire and nanosteel net
	endfunction

	private function Jump takes nothing returns nothing
		local unit u = GetTriggerUnit()
		local location l = GetSpellTargetLoc()
		local real x0
		local real y0
		local real x1 = GetLocationX(l)
		local real y1 = GetLocationY(l)
		local real dx
		local real dy
		local real xm = GetUnitX(u)
		local real ym = GetUnitY(u)
		local real distance
		local real maxjump = 270.0
		local integer currentlevel
		local integer momentum = 0
		if GetUnitAbilityLevel(u,'Bblo')>0 then //has sprint
			set momentum=1
			set maxjump=maxjump+20.0
			set x0 = GetUnitX(u)
			set y0 = GetUnitY(u)
		else
			call PolledWait(0.3)
			set x0 = GetUnitX(u)
			set y0 = GetUnitY(u)
			if SquareRoot(((xm-x0)*(xm-x0)+(ym-y0)*(ym-y0))+0.01)>25.0 then //achieved momentum
				set momentum = 1
				set maxjump=maxjump+65.0
			endif
		endif
		if GetUnitAbilityLevel(u,'B003')>0 then //Steroids
			set maxjump=maxjump+12.0
		endif
		if GetUnitAbilityLevel(u,'Bslo')>0 then //Fracture
			set maxjump=maxjump-60.0
		endif
		set currentlevel = GetTerrainCliffLevel(x0,y0)
		set dx = x0-x1
		set dy = y0-y1
		set distance = SquareRoot(((x0-x1)*(x0-x1)+(y0-y1)*(y0-y1))+0.01)
		if currentlevel==GetTerrainCliffLevel(x1,y1) then
			set maxjump=maxjump-50.0
		endif
		if GetSpellAbilityId()=='A05N' then //pet jump bonus
			set maxjump=maxjump+100.0
		endif
		if distance>maxjump then
			set x1 = x0 - dx*maxjump/distance
			set y1 = y0 - dy*maxjump/distance
		endif
		if currentlevel<GetTerrainCliffLevel(x1,y1) or (x1>GetRectMaxX(bj_mapInitialPlayableArea) or x1<GetRectMinX(bj_mapInitialPlayableArea) or y1>GetRectMaxY(bj_mapInitialPlayableArea) or y1<GetRectMinY(bj_mapInitialPlayableArea)) or distance<75 then //target point is too high, out of map, or self-jumping
			call IssueImmediateOrder(u,"holdposition")
		else
			if momentum==1 then
				call UnitAddAbility(u,'A07O') //Footsteps animation
			endif
			call hippityhoppity(u,x0,y0,x1,y1,momentum)
		endif
		call RemoveLocation(l)
		set l = null
		set u = null
	endfunction

	private function init takes nothing returns nothing
		local trigger t
		set t = CreateTrigger()
		call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT  )
		call TriggerAddCondition(t,Condition(function JumpConditions))
		call TriggerAddAction(t,function Jump)
	endfunction


endlibrary